/**
 * Copyright &copy; 2012-2016 <a href="https://github.com/thinkgem/jeesite">JeeSite</a> All rights reserved.
 */
package com.jy.springbootcmsservice.modules.gen.utils;

import com.jy.springbootcmsservice.common.config.Global;
import com.jy.springbootcmsservice.common.config.ProjectConfig;
import com.jy.springbootcmsservice.common.constant.Punctuation;
import com.jy.springbootcmsservice.common.utils.*;
import com.jy.springbootcmsservice.modules.gen.entity.*;
import com.jy.springbootcmsservice.modules.sys.entity.Area;
import com.jy.springbootcmsservice.modules.sys.entity.Office;
import com.jy.springbootcmsservice.modules.sys.entity.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 代码生成工具类
 * @author ThinkGem
 * @version 2013-11-16
 */
public class GenUtils {

	private static Logger logger = LoggerFactory.getLogger(GenUtils.class);
	private static ProjectConfig projectConfig = SpringContextHolder.getBean(ProjectConfig.class);

	/**
	 * javaType常量
	 */
	public static final String THIS_JAVA_TYPE = "This";
	public static final String DATE_JAVA_TYPE = "java.util.Date";
	public static final String STRING_JAVA_TYPE = "String";
	public static final String LIST_JAVA_TYPE = "java.util.List";
	public static final String GOOGLE_LIST_JAVA_TYPE = "com.google.common.collect.Lists";

	/**
	 * 初始化列属性字段
	 * @param table
	 */
	public static void initColumnField(Table table){
		for (TableColumn tableColumn : table.getTableColumnList()){
			
			// 如果是不是新增列，则跳过。
			if (StringUtils.isNotBlank(tableColumn.getId())){
				continue;
			}
			
			// 设置字段说明
			if (StringUtils.isBlank(tableColumn.getComments())){
				tableColumn.setComments(tableColumn.getName());
			}
			
			// 设置java类型
			if (StringUtils.startsWithIgnoreCase(tableColumn.getJdbcType(), "CHAR")
					|| StringUtils.startsWithIgnoreCase(tableColumn.getJdbcType(), "VARCHAR")
					|| StringUtils.startsWithIgnoreCase(tableColumn.getJdbcType(), "NARCHAR")){
				tableColumn.setJavaType("String");
			}else if (StringUtils.startsWithIgnoreCase(tableColumn.getJdbcType(), "DATETIME")
					|| StringUtils.startsWithIgnoreCase(tableColumn.getJdbcType(), "DATE")
					|| StringUtils.startsWithIgnoreCase(tableColumn.getJdbcType(), "TIMESTAMP")){
				tableColumn.setJavaType("java.util.Date");
				tableColumn.setShowType("dateselect");
			}else if (StringUtils.startsWithIgnoreCase(tableColumn.getJdbcType(), "BIGINT")
					|| StringUtils.startsWithIgnoreCase(tableColumn.getJdbcType(), "NUMBER")){
				// 如果是浮点型
				String[] ss = StringUtils.split(StringUtils.substringBetween(tableColumn.getJdbcType(), "(", ")"), Punctuation.COMMA);
				if (ss != null && ss.length == 2 && Integer.parseInt(ss[1])>0){
					tableColumn.setJavaType("Double");
				}
				// 如果是整形
				else if (ss != null && ss.length == 1 && Integer.parseInt(ss[0])<=10){
					tableColumn.setJavaType("Integer");
				}
				// 长整形
				else{
					tableColumn.setJavaType("Long");
				}
			}
			
			// 设置java字段名
			tableColumn.setJavaField(StringUtils.toCamelCase(tableColumn.getName()));
			
			// 是否是主键
			tableColumn.setIsPk(table.getPkList().contains(tableColumn.getName())?"1":"0");

			// 插入字段
			tableColumn.setIsInsert("1");
			
			// 编辑字段
			if (!StringUtils.equalsIgnoreCase(tableColumn.getName(), "id")
					&& !StringUtils.equalsIgnoreCase(tableColumn.getName(), "create_by")
					&& !StringUtils.equalsIgnoreCase(tableColumn.getName(), "create_date")
					&& !StringUtils.equalsIgnoreCase(tableColumn.getName(), "del_flag")){
				tableColumn.setIsEdit("1");
			}

			// 列表字段
			if (StringUtils.equalsIgnoreCase(tableColumn.getName(), "name")
					|| StringUtils.equalsIgnoreCase(tableColumn.getName(), "title")
					|| StringUtils.equalsIgnoreCase(tableColumn.getName(), "remarks")
					|| StringUtils.equalsIgnoreCase(tableColumn.getName(), "update_date")){
				tableColumn.setIsList("1");
			}
			
			// 查询字段
			if (StringUtils.equalsIgnoreCase(tableColumn.getName(), "name")
					|| StringUtils.equalsIgnoreCase(tableColumn.getName(), "title")){
				tableColumn.setIsQuery("1");
			}
			
			// 查询字段类型
			if (StringUtils.equalsIgnoreCase(tableColumn.getName(), "name")
					|| StringUtils.equalsIgnoreCase(tableColumn.getName(), "title")){
				tableColumn.setQueryType("like");
			}

			// 设置特定类型和字段名
			
			// 用户
			if (StringUtils.startsWithIgnoreCase(tableColumn.getName(), "user_id")){
				tableColumn.setJavaType(User.class.getName());
				tableColumn.setJavaField(tableColumn.getJavaField().replaceAll("Id", ".id|name"));
				tableColumn.setShowType("userselect");
			}
			// 部门
			else if (StringUtils.startsWithIgnoreCase(tableColumn.getName(), "office_id")){
				tableColumn.setJavaType(Office.class.getName());
				tableColumn.setJavaField(tableColumn.getJavaField().replaceAll("Id", ".id|name"));
				tableColumn.setShowType("officeselect");
			}
			// 区域
			else if (StringUtils.startsWithIgnoreCase(tableColumn.getName(), "area_id")){
				tableColumn.setJavaType(Area.class.getName());
				tableColumn.setJavaField(tableColumn.getJavaField().replaceAll("Id", ".id|name"));
				tableColumn.setShowType("areaselect");
			}
			// 创建者、更新者
			else if (StringUtils.startsWithIgnoreCase(tableColumn.getName(), "create_by")
					|| StringUtils.startsWithIgnoreCase(tableColumn.getName(), "update_by")){
				tableColumn.setJavaType(User.class.getName());
				tableColumn.setJavaField(tableColumn.getJavaField() + ".id");
			}
			// 创建时间、更新时间
			else if (StringUtils.startsWithIgnoreCase(tableColumn.getName(), "create_date")
					|| StringUtils.startsWithIgnoreCase(tableColumn.getName(), "update_date")){
				tableColumn.setShowType("dateselect");
			}
			// 备注、内容
			else if (StringUtils.equalsIgnoreCase(tableColumn.getName(), "remarks")
					|| StringUtils.equalsIgnoreCase(tableColumn.getName(), "content")){
				tableColumn.setShowType("textarea");
			}
			// 父级ID
			else if (StringUtils.equalsIgnoreCase(tableColumn.getName(), "parent_id")){
				tableColumn.setJavaType("This");
				tableColumn.setJavaField("parent.id|name");
				tableColumn.setShowType("treeselect");
			}
			// 所有父级ID
			else if (StringUtils.equalsIgnoreCase(tableColumn.getName(), "parent_ids")){
				tableColumn.setQueryType("like");
			}
			// 删除标记
			else if (StringUtils.equalsIgnoreCase(tableColumn.getName(), "del_flag")){
				tableColumn.setShowType("radiobox");
				tableColumn.setDictType("del_flag");
			}
		}
	}
	
	/**
	 * 获取模板路径
	 * @return
	 */
	public static String getTemplatePath(){
		try{
			File file = new DefaultResourceLoader().getResource("").getFile();
			if(file != null){
				return file.getAbsolutePath() + File.separator + StringUtils.replaceEach(GenUtils.class.getName(), 
						new String[]{"util."+GenUtils.class.getSimpleName(), "."}, new String[]{"template", File.separator});
			}			
		}catch(Exception e){
			logger.error("{}", e);
		}

		return "";
	}
	
	/**
	 * XML文件转换为对象
	 * @param fileName
	 * @param clazz
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T fileToObject(String fileName, Class<?> clazz){
		try {
			String pathName = "/templates/modules/gen/" + fileName;
			Resource resource = new ClassPathResource(pathName);
			InputStream is = resource.getInputStream();
			BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
			StringBuilder sb = new StringBuilder();  
			while (true) {
				String line = br.readLine();
				if (line == null){
					break;
				}
				sb.append(line).append("\r\n");
			}
			if (is != null) {
				is.close();
			}
			if (br != null) {
				br.close();
			}
			return (T) JaxbMapper.fromXml(sb.toString(), clazz);
		} catch (IOException e) {
			logger.warn("Error file convert: {}", e.getMessage());
		}
		return null;
	}
	
	/**
	 * 获取代码生成配置对象
	 * @return
	 */
	public static Config getConfig(){
		return fileToObject("config.xml", Config.class);
	}

	/**
	 * 根据分类获取模板列表
	 * @param config
	 * @param isChildTable 是否是子表
	 * @return
	 */
	public static List<Template> getTemplateList(Config config, String category, boolean isChildTable){
		List<Template> templateList = new ArrayList<>();
		if (config !=null && config.getCategoryList() != null && category !=  null){
			for (Category e : config.getCategoryList()){
				if (category.equals(e.getValue())){
					List<String> list = null;
					if (!isChildTable){
						list = e.getTemplate();
					}else{
						list = e.getChildTableTemplate();
					}
					if (list != null){
						for (String s : list){
							if (StringUtils.startsWith(s, Category.CATEGORY_REF)){
								templateList.addAll(getTemplateList(config, StringUtils.replace(s, Category.CATEGORY_REF, ""), false));
							}else{
								Template template = fileToObject(s, Template.class);
								if (template != null){
									templateList.add(template);
								}
							}
						}
					}
					break;
				}
			}
		}
		return templateList;
	}
	
	/**
	 * 获取数据模型
	 * @param scheme
	 * @return
	 */
	public static Map<String, Object> getDataModel(Scheme scheme){
		Map<String, Object> model = new HashMap<>(16);
		
		model.put("packageName", StringUtils.lowerCase(scheme.getPackageName()));
		model.put("lastPackageName", StringUtils.substringAfterLast((String)model.get("packageName"),"."));
		model.put("moduleName", StringUtils.lowerCase(scheme.getModuleName()));
		model.put("subModuleName", StringUtils.lowerCase(scheme.getSubModuleName()));
		model.put("className", StringUtils.uncapitalize(scheme.getTable().getClassName()));
		model.put("ClassName", StringUtils.capitalize(scheme.getTable().getClassName()));
		
		model.put("functionName", scheme.getFunctionName());
		model.put("functionNameSimple", scheme.getFunctionNameSimple());
		model.put("functionAuthor", StringUtils.isNotBlank(scheme.getFunctionAuthor())?scheme.getFunctionAuthor(): UserUtils.getUser().getName());
		model.put("functionVersion", DateUtils.getDate());
		
		model.put("urlPrefix", model.get("moduleName")+(StringUtils.isNotBlank(scheme.getSubModuleName())
				?"/"+StringUtils.lowerCase(scheme.getSubModuleName()):"")+"/"+model.get("className"));
		model.put("viewPrefix", model.get("urlPrefix"));
		model.put("permissionPrefix", model.get("moduleName")+(StringUtils.isNotBlank(scheme.getSubModuleName())
				?":"+StringUtils.lowerCase(scheme.getSubModuleName()):"")+":"+model.get("className"));
		
		model.put("dbType", projectConfig.getJdbcType());

		model.put("table", scheme.getTable());
		
		return model;
	}
	
	/**
	 * 生成到文件
	 * @param tpl
	 * @param model
	 * @param isReplaceFile
	 * @return
	 */
	public static String generateToFile(Template tpl, Map<String, Object> model, boolean isReplaceFile){
		// 获取生成文件
		String fileName = Global.getProjectPath() + File.separator 
				+ StringUtils.replaceEach(FreeMarkers.renderString(tpl.getFilePath() + "/", model), 
						new String[]{"//", "/", "."}, new String[]{File.separator, File.separator, File.separator})
				+ FreeMarkers.renderString(tpl.getFileName(), model);
		logger.debug(" fileName === " + fileName);

		// 获取生成文件内容
		String content = FreeMarkers.renderString(StringUtils.trimToEmpty(tpl.getContent()), model);
		logger.debug(" content === \r\n" + content);
		
		// 如果选择替换文件，则删除原文件
		if (isReplaceFile){
			FileUtils.deleteFile(fileName);
		}
		
		// 创建并写入文件
		if (FileUtils.createFile(fileName)){
			FileUtils.writeToFile(fileName, content, true);
			logger.debug(" file create === " + fileName);
			return "生成成功："+fileName+"<br/>";
		}else{
			logger.debug(" file extents === " + fileName);
			return "文件已存在："+fileName+"<br/>";
		}
	}
	
	public static void main(String[] args) {
		try {
			Config config = getConfig();
			System.out.println(config);
			System.out.println(JaxbMapper.toXml(config));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
}
